﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Calculator
{
    public partial class Calculator : Form
    {
        double count = 0;        //作为存储运算值

        public Calculator()
        {
            InitializeComponent();
        }

        //输入正负数
        private void btnNbChar_Click(object sender, EventArgs e)
        {
            if(rtxText.Text.Contains("-"))
            {
                rtxText.Text = rtxText.Text.Replace("-","");
            }
            else
            {
                rtxText.Text = "-" + rtxText.Text;
            }
        }

        //输入数字1
        private void btnNb1_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("1");
        }

        //输入数字2
        private void btnNb2_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("2");
        }

        //输入数字3
        private void btnNb3_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("3");
        }

        //输入数字0
        private void btnNb0_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("0");
        }

        //输入数字4
        private void btnNb4_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("4");
        }

        //输入数字5
        private void btnNb5_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("5");
        }

        //输入数字6
        private void btnNb6_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("6");
        }

        //输入数字7
        private void btnNb7_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("7");
        }

        //输入数字8
        private void btnNb8_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("8");
        }

        //输入数字9
        private void btnNb9_Click(object sender, EventArgs e)
        {
            rtxText.AppendText("9");
        }

        //输入符号.
        private void btnNbDian_Click(object sender, EventArgs e)
        {
            rtxText.AppendText(".");
        }

        //输入符号X
        private void btnMul_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "*");
            rtxText.Clear();
        }

        //输入符号-
        private void btnSub_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "-");
            rtxText.Clear();
        }

        //输入符号+
        private void btnAdd_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "+");
            rtxText.Clear();
        }

        //输入符号
        private void btnChu_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "/");
            rtxText.Clear();
        }

        //输入符号%
        private void btnZChu_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "%");
            rtxText.Clear();
        }

        //清空所有文本框
        private void btnClear_Click(object sender, EventArgs e)
        {
            rtxText.Clear();
            rtxCount.Clear();
        }

        //输入符号^
        private void btnZhiShu_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "^");
            rtxText.Clear();
        }

        //输入符号（
        private void btnZuoKuo_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + "(");
            rtxText.Clear();
        }

        //输入符号）
        private void btnYouKuo_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text + ")");
            rtxText.Clear();
        }

        //三角符号cos运算
        private void btnCos_Click(object sender, EventArgs e)
        {            
            count = Math.Cos(Convert.ToInt64(rtxText.Text)* Math.PI/180);
            rtxCount.Text = count.ToString();
            rtxText.Clear();
        }

        //三角符号sin运算
        private void btnSin_Click(object sender, EventArgs e)
        {
            count = Math.Sin(Convert.ToInt64(rtxText.Text) * Math.PI / 180);
            rtxCount.Text = count.ToString();
            rtxText.Clear();
        }

        //三角符号tan运算
        private void btnTan_Click(object sender, EventArgs e)
        {
            count = Math.Tan(Convert.ToInt64(rtxText.Text) * Math.PI / 180);
            rtxCount.Text = count.ToString();
            rtxText.Clear();
        }

        //对数符号log运算
        private void btnLog_Click(object sender, EventArgs e)
        {
            count = Math.Log(Convert.ToInt64(rtxText.Text));
            rtxCount.Text = count.ToString();
            rtxText.Clear();
        }
 
        //输入框清空
        private void btnClearInput_Click(object sender, EventArgs e)
        {
            rtxText.Clear();
        }

        public void ActualMain()
        {
            try
            {
                string ep = rtxCount.Text;                  //输入字符串
                filter(ref ep);
                if (numOfCharInStr('(', ep) != numOfCharInStr(')', ep))
                    throw new Exception();
                while (hasChar(ep, '('))
                {
                    int L, R, j, LL;
                    string strfunc = "";
                    R = ep.IndexOf(')');
                    j = R - 1;
                    while (ep[j] != '(')
                    { j--; }
                    L = j;
                    j--;
                    while (j >= 0 && j < ep.Length && ep[j] >= 97 && ep[j] <= 122)
                    {
                        strfunc += ep[j];
                        j--;
                    }
                    LL = j + 1;
                    reverseStr(ref strfunc);
                    if (strfunc == "")
                        ep = ep.Replace(ep.Substring(L, R - L + 1), jjcc(ep.Substring(L + 1, R - L - 1)));
                    else
                    {
                        string result = function(strfunc, Convert.ToDouble(jjcc(ep.Substring(L + 1, R - L - 1))));
                        ep = ep.Replace(ep.Substring(LL, R - LL + 1), result);
                    }
                }
                rtxCount.AppendText("\n= " + jjcc(ep) + "\n");
                rtxCount.Focus();                               
                rtxCount.Select(rtxCount.TextLength, 0);
                rtxCount.ScrollToCaret();
            }
            catch
            {
                MessageBox.Show("发生错误\n");
            }
        }


        ///转半角的函数(DBC case) <summary> 
        ///转半角的函数(DBC case)
        /// </summary>  
        /// <param name="input">任意字符串</param>  
        /// <returns>半角字符串</returns>  
        ///<remarks>  
        ///全角空格为12288，半角空格为32  
        ///其他字符半角(33-126)与全角(65281-65374)的对应关系是：均相差65248  
        ///</remarks>  
        public static string ToDBC(string input)
        {
            char[] c = input.ToCharArray();
            for (int i = 0; i < c.Length; i++)
            {
                if (c[i] == 12288) { c[i] = (char)32; continue; }//全角空格
                if (c[i] > 65280 && c[i] < 65375) { c[i] = (char)(c[i] - 65248); } //其他全角字符
            }
            return new string(c);
        }

        //算术符处理
        public static void filter(ref string eq)
        {
            eq = ToDBC(eq);
            string process = "";
            char[] terms = eq.ToCharArray();
            for (int i = 0; i < eq.Length; i++)
            {
                int c = terms[i];
                if ((c >= 97 && c <= 122 || (c >= 48 && c <= 57)) || c == '+' || c == '-' || c == '*' || c == '/' || c == '^'
                    || c == '(' || c == ')' || c == '.' || c == '%' || c == '!')
                {
                    process += terms[i];
                }
            }
            eq = process;
        }

        public static void reverseStr(ref string str)
        {
            char[] chs = str.ToCharArray();
            Array.Reverse(chs);
            str = new string(chs);
        }

        //逻辑运算
        public static string function(string str, double num)
        {
            double output = 0;
            if (str == "abs")
                output = Math.Abs(num);
            else if (str == "arccos")
                output = Math.Acos(num);
            else if (str == "arcsin")
                output = Math.Asin(num);
            else if (str == "arctan")
                output = Math.Atan(num);
            else if (str == "cos")
                output = Math.Cos(num);
            else if (str == "cosh")
                output = Math.Cosh(num);
            else if (str == "exp")
                output = Math.Exp(num);
            else if (str == "floor")
                output = Math.Floor(num);
            else if (str == "log")
                output = Math.Log10(num);
            else if (str == "ln")
                output = Math.Log(num);
            else if (str == "sin")
                output = Math.Sin(num);
            else if (str == "sinh")
                output = Math.Sinh(num);
            else if (str == "sqrt")
                output = Math.Sqrt(num);
            else if (str == "tan")
                output = Math.Tan(num);
            else if (str == "tanh")
                output = Math.Tanh(num);
            return output.ToString();
        }


        public static double F(double n)
        {
            if (n < 0) throw new Exception();
            if (n % 1 == 0)
            {
                if (n != 0)
                    return n * F(n - 1);
                else
                    return 1;
            }
            else return gam1(n + 1);
        }

        public static double gam1(double x)
        {
            int i;
            double y, t, s, u;
            double[] a ={ 0.0000677106,-0.0003442342,
                   0.0015397681,-0.0024467480,0.0109736958,
                   -0.0002109075,0.0742379071,0.0815782188,
                   0.4118402518,0.4227843370,1.0};
            if (x <= 0.0)
            { throw new Exception(); }
            y = x;
            if (y <= 1.0)
            { t = 1.0 / (y * (y + 1.0)); y = y + 2.0; }
            else if (y <= 2.0)
            { t = 1.0 / y; y = y + 1.0; }
            else if (y <= 3.0) t = 1.0;
            else
            {
                t = 1.0;
                while (y > 3.0)
                { y = y - 1.0; t = t * y; }
            }
            s = a[0]; u = y - 2.0;
            for (i = 1; i <= 10; i++)
                s = s * u + a[i];
            s = s * t;
            return s;
        }

        //计算优先级
        public static string jjcc(string ep)
        {
            char[] epc = ep.ToCharArray();
            while (hasChar(ep, '^') || hasChar(ep, '!'))
            {
                for (int i = 0; i < epc.Length; i++)
                {
                    int j, flag;
                    double numl, numr;
                    string strl = "", strr = "", strFinal = "", strpre;
                    char[] strlc;
                    if (epc[i] == '^')
                    {
                        j = i - 1;
                        while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                        {
                            strl += epc[j];
                            j--;
                        }
                        flag = j;
                        strlc = strl.ToCharArray();
                        Array.Reverse(strlc);
                        strl = new string(strlc);
                        if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                        {
                            if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                strl = "-" + strl;
                        }
                        flag = j = i + 1;
                        if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                        while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                        {
                            strr += epc[j];
                            j++;
                        }
                        if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                        strpre = strl + "^" + strr;
                        numl = Convert.ToDouble(strl);
                        numr = Convert.ToDouble(strr);
                        strFinal = (Math.Pow(numl, numr)).ToString();
                        ep = ep.Replace(strpre, strFinal);
                        epc = ep.ToCharArray();
                    }
                    else if (epc[i] == '!')
                    {
                        j = i - 1;
                        while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                        {
                            strl += epc[j];
                            j--;
                        }
                        flag = j;
                        strlc = strl.ToCharArray();
                        Array.Reverse(strlc);
                        strl = new string(strlc);
                        if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                        {
                            if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                strl = "-" + strl;
                        }
                        strpre = strl + "!";
                        numl = Convert.ToDouble(strl);
                        strFinal = (F(numl)).ToString();
                        ep = ep.Replace(strpre, strFinal);
                        epc = ep.ToCharArray();
                    }
                }
            }
            while (hasChar(ep, '*') || hasChar(ep, '/') || hasChar(ep, '%'))
            {
                for (int i = 0; i < epc.Length; i++)
                {
                    int j, flag;
                    double numl, numr;
                    string strl = "", strr = "", strFinal = "", strpre;
                    char[] strlc;
                    switch (epc[i])
                    {
                        case '*':
                            j = i - 1;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strl += epc[j];
                                j--;
                            }
                            flag = j;
                            strlc = strl.ToCharArray();
                            Array.Reverse(strlc);
                            strl = new string(strlc);
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                            {
                                if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                    strl = "-" + strl;
                            }
                            flag = j = i + 1;
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strr += epc[j];
                                j++;
                            }
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                            strpre = strl + "*" + strr;
                            numl = Convert.ToDouble(strl);
                            numr = Convert.ToDouble(strr);
                            strFinal = (numl * numr).ToString();
                            ep = ep.Replace(strpre, strFinal);
                            epc = ep.ToCharArray();
                            break;
                        case '/':
                            j = i - 1;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strl += epc[j];
                                j--;
                            }
                            flag = j;
                            strlc = strl.ToCharArray();
                            Array.Reverse(strlc);
                            strl = new string(strlc);
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                            {
                                if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                    strl = "-" + strl;
                            }
                            flag = j = i + 1;
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strr += epc[j];
                                j++;
                            }
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                            strpre = strl + "/" + strr;
                            numl = Convert.ToDouble(strl);
                            numr = Convert.ToDouble(strr);
                            strFinal = (numl / numr).ToString();
                            ep = ep.Replace(strpre, strFinal);
                            epc = ep.ToCharArray();
                            break;
                        case '%':
                            j = i - 1;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strl += epc[j];
                                j--;
                            }
                            flag = j;
                            strlc = strl.ToCharArray();
                            Array.Reverse(strlc);
                            strl = new string(strlc);
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                            {
                                if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                    strl = "-" + strl;
                            }
                            flag = j = i + 1;
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strr += epc[j];
                                j++;
                            }
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                            strpre = strl + "%" + strr;
                            numl = Convert.ToDouble(strl);
                            numr = Convert.ToDouble(strr);
                            strFinal = (numl % numr).ToString();
                            ep = ep.Replace(strpre, strFinal);
                            epc = ep.ToCharArray();
                            break;
                    }
                }
            }
            while (hasChar(ep, '+') || hasChar(ep, '-'))
            {
                for (int i = 0; i < epc.Length; i++)
                {
                    int j, flag;
                    double numl, numr;
                    string strl = "", strr = "", strFinal = "", strpre;
                    char[] strlc;
                    switch (epc[i])
                    {
                        case '+':
                            j = i - 1;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strl += epc[j];
                                j--;
                            }
                            flag = j;
                            strlc = strl.ToCharArray();
                            Array.Reverse(strlc);
                            strl = new string(strlc);
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                            {
                                if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                    strl = "-" + strl;
                            }
                            flag = j = i + 1;
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strr += epc[j];
                                j++;
                            }
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                            strpre = strl + "+" + strr;
                            numl = Convert.ToDouble(strl);
                            numr = Convert.ToDouble(strr);
                            strFinal = (numl + numr).ToString();
                            ep = ep.Replace(strpre, strFinal);
                            epc = ep.ToCharArray();
                            break;
                        case '-':
                            j = i - 1;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strl += epc[j];
                                j--;
                            }
                            if (strl == "") break;
                            flag = j;
                            strlc = strl.ToCharArray();
                            Array.Reverse(strlc);
                            strl = new string(strlc);
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-')
                            {
                                if (!(flag > 0 && flag < epc.Length && epc[flag - 1] >= 48 && epc[flag - 1] <= 57))
                                    strl = "-" + strl;
                            }
                            flag = j = i + 1;
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') j++;
                            while (j >= 0 && j < epc.Length && (epc[j] >= 48 && epc[j] <= 57 || epc[j] == '.'))
                            {
                                strr += epc[j];
                                j++;
                            }
                            if (flag >= 0 && flag < epc.Length && epc[flag] == '-') strr = "-" + strr;
                            strpre = strl + "-" + strr;
                            numl = Convert.ToDouble(strl);
                            numr = Convert.ToDouble(strr);
                            strFinal = (numl - numr).ToString();
                            ep = ep.Replace(strpre, strFinal);
                            epc = ep.ToCharArray();
                            break;
                    }
                }
            }
            return ep;
        }
        
        //是否有字符串
        public static bool hasChar(string str, char c)
        {
            char[] chs = str.ToCharArray();
            if (c == '-')
            {
                for (int i = 1; i < chs.Length; i++)
                {
                    if (chs[i] == c && chs[i - 1] >= 48 && chs[i - 1] <= 57)
                        return true;
                }
            }
            else
                foreach (char ch in chs)
                {
                    if (ch == c) return true;
                }
            return false;
        }

        public static int numOfCharInStr(char c, string str)
        {
            int n = 0;
            char[] cs = str.ToCharArray();
            foreach (char ch in cs)
            {
                if (ch == c) n++;
            }
            return n;
        }

        //求值
        private void btnEqual_Click(object sender, EventArgs e)
        {
            rtxCount.AppendText(rtxText.Text);
            if (rtxCount.Text != "")
                ActualMain();
        }     
    }
}
